import cv2
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] 
plt.rcParams.update({'font.size': 6})

# 使用imread函数打开图片
img = cv2.imread('test.jpg', 0)
img_np = np.array(img)
img = img_np[500:img_np.shape[0]-100, 50:img_np.shape[1]-50]
img_1 = cv2.cvtColor(img.copy(), cv2.COLOR_GRAY2RGB)
# 全局阈值处理为二值图像
_, black = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

# 腐蚀操作去除
kernel = np.ones((3, 3), np.uint8)
corroded_img = cv2.erode(black, kernel, iterations=3)  

# 中值滤波
restored_img = cv2.medianBlur(corroded_img, 5)

# 膨胀操作还原字符
restored_img = cv2.dilate(restored_img, kernel, iterations=3)

# 闭运算
closed_kernel = np.ones((3, 3), np.uint8)
closed_img = cv2.morphologyEx(restored_img, cv2.MORPH_CLOSE, closed_kernel, iterations=25)

# canney边缘检测
edges = cv2.Canny(closed_img, 100, 200)

# 把灰度图像转化成二值图像
thresh, binary_image = cv2.threshold(edges, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# 轮廓检测
contours, hierarchy = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# 设置周长阈值
length_threshold = 250
i = 1
for contour in contours:
    # 计算轮廓周长
    perimeter = cv2.arcLength(contour, True)
    if perimeter > length_threshold:
        # 计算轮廓的边界框
        x, y, w, h = cv2.boundingRect(contour)
        # 在图像上绘制边界框
        cv2.rectangle(img_1, (x-40, y-10), (x+w+40, y+h+35), (0, 255, 0), 10)
        # 获取字符区域
        character = img[y-10:y+h+35, x-40:x+w+40]
        # 保存字符区域
        cv2.imwrite('./out/'+str(i)+'.png', character)
        i += 1

fig, axs = plt.subplots(1, 7, figsize=(20, 5))
axs[0].imshow(img, cmap='gray')
axs[0].axis('off')
axs[0].set_title('原始图像')

axs[1].imshow(black, cmap='gray')
axs[1].axis('off')
axs[1].set_title('全局阈值处理->二值图像')

axs[2].imshow(corroded_img, cmap='gray')
axs[2].axis('off')
axs[2].set_title('腐蚀操作->去除噪点')

axs[3].imshow(restored_img, cmap='gray')
axs[3].axis('off')
axs[3].set_title('膨胀操作+中值滤波->突出文字')

axs[4].imshow(closed_img, cmap='gray')
axs[4].axis('off')
axs[4].set_title('闭运算->填充文字区域')

axs[5].imshow(edges, cmap='gray')
axs[5].axis('off')
axs[5].set_title('Canney边缘检测')

axs[6].imshow(img_1)
axs[6].axis('off')
axs[6].set_title('边框提取')

plt.show()

